package com.ruoyi.common.utils.wechat;

import com.ruoyi.common.core.domain.dto.WechatPayParam;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.uuid.IdUtils;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.partnerpayments.jsapi.model.Transaction;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.model.Amount;
import com.wechat.pay.java.service.payments.jsapi.model.Payer;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayWithRequestPaymentResponse;
import com.wechat.pay.java.service.refund.model.AmountReq;
import com.wechat.pay.java.service.refund.model.CreateRequest;
import com.wechat.pay.java.service.refund.model.Refund;
import com.wechat.pay.java.service.refund.model.RefundNotification;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 小程序： 直连商户下单
 */
@Component
public class WechatPayV3 {

    @Autowired
    private WechatProperties wechatProperties;


    @Autowired
    RedisCache redisCache;

    /**
     * jsapi微信支付功能
     */
    public PrepayWithRequestPaymentResponse weChatJsApiPay(WechatPayParam wechatPayParam) {
        JsapiServiceExtension jsapiServiceExtension = new JsapiServiceExtension.Builder().config(WechatProperties.certificateConfig).build();
        PrepayRequest request = new PrepayRequest();
        Amount amount = new Amount();
        amount.setTotal(wechatPayParam.getPayPrice());
        request.setAmount(amount);
        request.setAppid(wechatProperties.getAppId());
        request.setMchid(wechatProperties.getMchId());
        request.setNotifyUrl(wechatProperties.getPayNotifyUrl());
        request.setDescription(wechatPayParam.getDescription());
        request.setOutTradeNo(wechatPayParam.getOutTradeNo());
        Payer payer = new Payer();
        payer.setOpenid(wechatPayParam.getOpenid());
        request.setPayer(payer);
        // response包含了调起支付所需的所有参数，可直接用于前端调起支付
        PrepayWithRequestPaymentResponse response = jsapiServiceExtension.prepayWithRequestPayment(request);
        return response;
    }

    /**
     * jsapi支付回调校验
     * @param request
     * @return
     */
    public Transaction weChatJsapiPayCallback(HttpServletRequest request){
        String data = null;
        try {
            data = request.getReader().lines().collect(Collectors.joining());
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 构造 RequestParam
        RequestParam requestParam = new RequestParam.Builder()
                .serialNumber(request.getHeader("Wechatpay-Serial"))
                .nonce(request.getHeader("Wechatpay-Nonce"))
                .signature(request.getHeader("Wechatpay-Signature"))
                .timestamp(request.getHeader("Wechatpay-Timestamp"))
                .body(data)
                .build();


        // 初始化 NotificationParser
        NotificationParser parser = new NotificationParser(WechatProperties.certificateConfig);

        // 以支付通知回调为例，验签、解密并转换成 Transaction
        Transaction transaction = parser.parse(requestParam, Transaction.class);
        String key = "weChatJsapiPayCallback:" + transaction.getTransactionId();
        String cacheObject = redisCache.getCacheObject(key);
        Assert.isTrue(StringUtils.isBlank(cacheObject), "接口调用频繁");
        redisCache.setCacheObject(key, transaction.getTransactionId(), 10, TimeUnit.MINUTES);

        return transaction;
    }

    /**
     * 微信退款
     * @param wechatPayParam
     * @return
     */
    public Refund wechatRefund(WechatPayParam wechatPayParam){
        CreateRequest request = new CreateRequest();
        request.setTransactionId(wechatPayParam.getTransactionId());
        request.setOutTradeNo(wechatPayParam.getOutTradeNo());
        request.setReason(wechatPayParam.getReason());
        request.setNotifyUrl(wechatProperties.getRefundNotifyUrl());
        request.setOutRefundNo(IdUtils.fastSimpleUUID());
        AmountReq amount = new AmountReq();
        amount.setRefund(wechatPayParam.getRefundPrice().longValue());
        amount.setTotal(wechatPayParam.getPayPrice().longValue());
        amount.setTotal(1L);
        amount.setCurrency("CNY");
        request.setAmount(amount);
        return WechatProperties.refundService.create(request);
    }

    /**
     * 退款回调校验
     * @param request
     * @return
     */
    public RefundNotification refundCallback(HttpServletRequest request) {
        String data = null;
        try {
            data = request.getReader().lines().collect(Collectors.joining());
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 构造 RequestParam
        RequestParam requestParam = new RequestParam.Builder()
                .serialNumber(request.getHeader("Wechatpay-Serial"))
                .nonce(request.getHeader("Wechatpay-Nonce"))
                .signature(request.getHeader("Wechatpay-Signature"))
                .timestamp(request.getHeader("Wechatpay-Timestamp"))
                .body(data)
                .build();


        // 初始化 NotificationParser
        NotificationParser parser = new NotificationParser(WechatProperties.certificateConfig);

        // 以支付通知回调为例，验签、解密并转换成 Transaction
        RefundNotification parse = parser.parse(requestParam, RefundNotification.class);
        String key = "refundCallback:" + parse.getRefundId();
        String cacheObject = redisCache.getCacheObject(key);
        Assert.isTrue(StringUtils.isBlank(cacheObject), "接口调用频繁");
        redisCache.setCacheObject(key, parse.getRefundId(), 10, TimeUnit.MINUTES);
        return parse;
    }
}
